package com.groupbuying.store.service.impl;

import com.groupbuying.store.connector.SettleFeign;
import com.groupbuying.store.connector.SysconfigFeign;
import com.groupbuying.store.constants.CommonConstants;
import com.groupbuying.store.constants.StoreVirtualOperConstants;
import com.groupbuying.store.dao.StoreCapitalVirtualAccountDao;
import com.groupbuying.store.domain.StoreCapitalVirtualAccountDO;
import com.groupbuying.store.domain.StoreCapitalVirtualAccountDetailDO;
import com.groupbuying.store.domain.StoreMainInfoDO;
import com.groupbuying.store.pojo.StoreCapitalVirtualAccountEnum;
import com.groupbuying.store.pojo.StoreMainInfoEnum;
import com.groupbuying.store.service.StoreCapitalVirtualAccountDetailService;
import com.groupbuying.store.service.StoreCapitalVirtualAccountService;
import com.groupbuying.store.service.StoreCompanyInfoService;
import com.groupbuying.store.service.StoreMainInfoService;
import com.groupbuying.store.utils.DateFormatHelper;
import com.groupbuying.store.utils.JSONUtils;
import com.groupbuying.store.utils.RedisUtils;
import com.groupbuying.store.utils.ReturnUtils;
import com.groupbuying.store.utils.apiresult.ApiResult;
import com.groupbuying.store.utils.apiresult.ApiResultCode;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;


@Service
public class StoreCapitalVirtualAccountServiceImpl implements StoreCapitalVirtualAccountService {

    private static Logger log = LoggerFactory.getLogger(StoreCapitalVirtualAccountServiceImpl.class);


    @Autowired
    private StoreCapitalVirtualAccountDao storeCapitalVirtualAccountDao;

    @Autowired
    private StoreCompanyInfoService storeCompanyInfoService;

    @Autowired
    @Lazy
    private StoreMainInfoService storeMainInfoService;

    @Autowired
    private StoreCapitalVirtualAccountDetailService storeCapitalVirtualAccountDetailService;

    @Autowired
    private SysconfigFeign sysconfigFeign;

    @Autowired
    private SettleFeign settleFeign;

    @Autowired
    private RedisUtils redisUtils;

    @Override
    public StoreCapitalVirtualAccountDO get(String uuid) {
        return storeCapitalVirtualAccountDao.get(uuid);
    }

    @Override
    public List<StoreCapitalVirtualAccountDO> list(Map<String, Object> map) {
        return storeCapitalVirtualAccountDao.list(map);
    }

    @Override
    public int count(Map<String, Object> map) {
        return storeCapitalVirtualAccountDao.count(map);
    }

    @Override
    public int save(StoreCapitalVirtualAccountDO storeCapitalVirtualAccount) {
        return storeCapitalVirtualAccountDao.save(storeCapitalVirtualAccount);
    }

    @Override
    public int update(StoreCapitalVirtualAccountDO storeCapitalVirtualAccount) {
        return storeCapitalVirtualAccountDao.update(storeCapitalVirtualAccount);
    }

    @Override
    public int remove(String uuid) {
        return storeCapitalVirtualAccountDao.remove(uuid);
    }

    @Override
    public int batchRemove(String[] uuids) {
        return storeCapitalVirtualAccountDao.batchRemove(uuids);
    }

    @Override
    public StoreCapitalVirtualAccountDO createStoreVirtualAccount(String storeUuid, String storeno, String storename, String mobile, StoreCapitalVirtualAccountDO storeCapitalVirtualAccount) {
        storeCapitalVirtualAccount.setStoreuuid(storeUuid);
        storeCapitalVirtualAccount.setStoreno(storeno);
        storeCapitalVirtualAccount.setStorename(storename);
//        storeCapitalVirtualAccount.setMobile(mobile);
        storeCapitalVirtualAccount.setPublicornom(storeCapitalVirtualAccount.getAccounttype());
        storeCapitalVirtualAccount.setDocumenttype("00");
        storeCapitalVirtualAccount.setVirtualstate(StoreCapitalVirtualAccountEnum.NORMAL);
        storeCapitalVirtualAccount.setDelflag(CommonConstants.COMMON_FLAG_UNDEL);
        storeCapitalVirtualAccount.setVersion(0);
        storeCapitalVirtualAccount.setPunishintegral(0);
        storeCapitalVirtualAccount.setUuid(sysconfigFeign.getUuidByLeaf());
        this.save(storeCapitalVirtualAccount);
        return storeCapitalVirtualAccount;
    }

    @Override
    public StoreCapitalVirtualAccountDO getStoreCapitalVirtualAccountByStoreUuid(String storeUuid) {
        Map<String, Object> params = new HashMap<>();
        params.put("storeuuid", storeUuid);
        params.put("delflag", CommonConstants.COMMON_FLAG_UNDEL);
        List<StoreCapitalVirtualAccountDO> list = storeCapitalVirtualAccountDao.list(params);
        return list != null && list.size() > 0 ? list.get(0) : null;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ApiResult dealStoreVirtualAccount(Map<String, Object> param) {

        Object temp = param.get("sum");
        BigDecimal sum = new BigDecimal(temp.toString());
        temp = param.get("orderNo");
        String orderNo = temp.toString();
        temp = param.get("storeUuid");
        String storeUuid = temp.toString();
        temp = param.get("businessType");
        String businessType = temp.toString();
        temp = param.get("customerUuid");
        String customerUuid = temp.toString();
        temp = param.get("inOrOut");
        String inOrOut = temp.toString();
        temp = param.get("description");
        String description = temp != null ? temp.toString() : null;
        temp = param.get("operCashAmount");
        BigDecimal operCashAmount = temp != null ? new BigDecimal(temp.toString()) : null;
        temp = param.get("operBalanceAmount");
        BigDecimal operBalanceAmount = temp != null ? new BigDecimal(temp.toString()) : null;
        temp = param.get("operIntegralAmount");
        BigDecimal operIntegralAmount = temp != null ? new BigDecimal(temp.toString()) : null;

        if (sum == null || StringUtils.isBlank(orderNo) || StringUtils.isBlank(storeUuid) || StringUtils.isBlank(businessType) || StringUtils.isBlank(customerUuid) || StringUtils.isBlank(inOrOut) || StringUtils.isBlank(description)
                || operCashAmount == null || operBalanceAmount == null || operIntegralAmount == null) {
            return ApiResult.paramIsNull();
        }

        String redisLockKey = "changeMoney" + storeUuid;
        String timeStamp = "" + System.currentTimeMillis();
        log.error("金额流转1");
        /**
         * 分布式锁
         */
        try {
            while (!redisUtils.setIfAbsent(redisLockKey, timeStamp, 3L)) {
                Thread.sleep(10L);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        log.error("金额流转2");
        //订单幂等性校验
        boolean isRepeat = isRepeatOrder(orderNo, storeUuid, businessType, inOrOut);
        if(isRepeat){
            log.error("订单号：{} 重复操作商户金额",storeUuid);
            return ApiResult.failure(String.format("订单号：%s 重复操作商户金额", storeUuid));
        }
        log.error("金额流转3");
        try {
            // cas 操作
            while (true) {
                StoreCapitalVirtualAccountDO storeCapitalVirtualAccount = this.getStoreCapitalVirtualAccountByStoreUuid(storeUuid);
                int updateFlag = 0;
                BigDecimal oldVirtualMoney = storeCapitalVirtualAccount.getVirtualmoney();
                BigDecimal oldFreezevirtualmoney = storeCapitalVirtualAccount.getFreezevirtualmoney();
                BigDecimal freezevirtualmoney = oldFreezevirtualmoney;
                BigDecimal virtualmoney = oldVirtualMoney;
                // 详细金额快照
                BigDecimal cashAmount = storeCapitalVirtualAccount.getCashAmount();
                BigDecimal balanceAmount = storeCapitalVirtualAccount.getBalanceAmount();
                BigDecimal integralAmount = storeCapitalVirtualAccount.getIntegralAmount();
                // 详细金额操作明细
                String uuid = storeCapitalVirtualAccount.getUuid();

                //虚拟账户入账
                if (StoreVirtualOperConstants.IN_MONEY.equals(inOrOut)) {

                    virtualmoney = oldVirtualMoney.add(sum);
                    balanceAmount = balanceAmount.add(operBalanceAmount);
                    cashAmount = cashAmount.add(operCashAmount);
                    integralAmount = integralAmount.add(operIntegralAmount);
                    log.error("金额流转3。1");
                    //修改金额
                    updateFlag = updateMoney(uuid, virtualmoney, freezevirtualmoney, oldVirtualMoney, oldFreezevirtualmoney, cashAmount, balanceAmount, integralAmount);
                } else if (StoreVirtualOperConstants.OUT_MONEY.equals(inOrOut)) {
                    //虚拟账户出账
                    if (sum.compareTo(oldFreezevirtualmoney) == 1) {
                        return ApiResult.failure("虚拟账户出账金额不足以减扣");
                    }
                    virtualmoney = oldVirtualMoney.subtract(sum);
                    balanceAmount = balanceAmount.subtract(operBalanceAmount);
                    cashAmount = cashAmount.subtract(operCashAmount);
                    integralAmount = integralAmount.subtract(operIntegralAmount);

                    //修改金额
                    updateFlag = updateMoney(uuid, virtualmoney, freezevirtualmoney, oldVirtualMoney, oldFreezevirtualmoney, cashAmount, balanceAmount, integralAmount);
                } else {
                    return ApiResult.failure("未知操作类型");
                }
                if (updateFlag == 0) {
                    continue;
                }
                log.error("金额流转3。2");
                //生成流水
                storeCapitalVirtualAccountDetailService.createStoreAccountLog(storeUuid, storeCapitalVirtualAccount.getStoreno(), businessType, inOrOut, sum, virtualmoney, freezevirtualmoney, orderNo, description, customerUuid, cashAmount, balanceAmount, integralAmount, operCashAmount, operBalanceAmount, operIntegralAmount);
                log.error("金额流转4");
                return ApiResult.success();
            }
        } catch (Exception e){
            e.printStackTrace();
            log.error(e.getMessage());
        }finally {
            Object redisLockValue = redisUtils.getValue(redisLockKey);
            if (redisLockValue != null && timeStamp.equals(redisLockValue.toString())) {
                redisUtils.delKey(redisLockKey);
            }
        }
            return ApiResult.failure();
    }

    public boolean isRepeatOrder(String orderNo, String storeUuid, String businessType, String inOrOut) {
        Map queryParam = new HashMap();
        queryParam.put("billno",orderNo);
        queryParam.put("businesstype",businessType);
        queryParam.put("storeuuid",storeUuid);
        queryParam.put("inorout",inOrOut);
        queryParam.put("delflag", CommonConstants.COMMON_FLAG_UNDEL);

        List<StoreCapitalVirtualAccountDetailDO> storeCapitalVirtualAccountDetailDOList = storeCapitalVirtualAccountDetailService.list(queryParam);
        log.error("查询记录详情storeCapitalVirtualAccountDetailDOList");

        return storeCapitalVirtualAccountDetailDOList!=null && storeCapitalVirtualAccountDetailDOList.size()>0;
    }

    public int updateMoney(String uuid, BigDecimal virtualmoney, BigDecimal freezevirtualmoney, BigDecimal oldVirtualMoney, BigDecimal oldFreezevirtualmoney, BigDecimal cashAmount, BigDecimal balanceAmount, BigDecimal integralAmount) {

        Map upateMap = new HashMap();
        upateMap.put("uuid", uuid);
        upateMap.put("virtualmoney", virtualmoney);
        upateMap.put("freezevirtualmoney", freezevirtualmoney);
        upateMap.put("opetime", DateFormatHelper.getNowTimeStr());
        upateMap.put("oldVirtualMoney", oldVirtualMoney);
        upateMap.put("oldFreezevirtualmoney", oldFreezevirtualmoney);
        upateMap.put("cashAmount", cashAmount);
        upateMap.put("balanceAmount", balanceAmount);
        upateMap.put("integralAmount", integralAmount);

        return storeCapitalVirtualAccountDao.updateMoney(upateMap);
    }

    @Override
    public Object queryStoreVirtualAccountInfo(Map<String, Object> param) {

        try {
            Object temp = param.get("storeUuid");
            String storeUuid = temp == null ? temp.toString() : null;

            Map<String, Object> map = new HashMap<>();
            param.put("delFlag", CommonConstants.COMMON_FLAG_UNDEL);
            param.put("storeUuid", storeUuid);
            List<StoreCapitalVirtualAccountDO> list = storeCapitalVirtualAccountDao.list(map);
            StoreCapitalVirtualAccountDO storeCapitalVirtualAccount = list != null && list.size() > 0 ? list.get(0) : null;

            Map<String, Object> result = new HashMap<>();
            result.put("storeName", storeCapitalVirtualAccount.getStorename());
            result.put("virtualMoney", storeCapitalVirtualAccount.getVirtualmoney());

            return ReturnUtils.createReturnResult(ApiResultCode.OPRSUCCESS.code(), ApiResultCode.OPRSUCCESS.message(), true, JSONUtils.beanToJson(result));
        } catch (Exception e) {
            e.printStackTrace();
            return ReturnUtils.createReturnResult(ApiResultCode.OPRFAILURE.code(), ApiResultCode.OPRFAILURE.message(), false, "");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ApiResult freezeOrUnFreezeVirtualMoney(Map<String, Object> params) {
        Object temp = params.get("storeUuid");
        String storeUuid = temp != null ? temp.toString() : null;
        temp = params.get("operAmount");
        BigDecimal operAmount = temp != null ? new BigDecimal(temp.toString()) : null;
        temp = params.get("operType");
        String operType = temp != null ? temp.toString() : null;
        temp = params.get("businessType");
        String businessType = temp != null ? temp.toString() : null;
        temp = params.get("customerUuid");
        String customerUuid = temp != null ? temp.toString() : null;
        temp = params.get("orderNo");
        String orderNo = temp != null ? temp.toString() : null;
        temp = params.get("description");
        String description = temp != null ? temp.toString() : null;
        temp = params.get("operCashAmount");
        BigDecimal operCashAmount = temp != null ? new BigDecimal(temp.toString()) : null;
        temp = params.get("operBalanceAmount");
        BigDecimal operBalanceAmount = temp != null ? new BigDecimal(temp.toString()) : null;
        temp = params.get("operIntegralAmount");
        BigDecimal operIntegralAmount = temp != null ? new BigDecimal(temp.toString()) : null;


        if (StringUtils.isBlank(storeUuid) || operAmount == null || StringUtils.isBlank(operType) || StringUtils.isBlank(businessType) || StringUtils.isBlank(customerUuid) || StringUtils.isBlank(orderNo)
                || StringUtils.isBlank(description) || operCashAmount == null || operBalanceAmount == null || operIntegralAmount == null) {
            return ApiResult.paramIsNull();
        }

        String redisLockKey = "changeMoney" + storeUuid;
        String timeStamp = "" + System.currentTimeMillis();
        /**
         * 分布式锁
         */
        try {
            while (!redisUtils.setIfAbsent(redisLockKey, timeStamp, 3L)) {
                Thread.sleep(100L);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        //订单幂等性校验
        boolean isRepeat = isRepeatOrder(orderNo, storeUuid, businessType, operType);
        if(isRepeat){
            log.error("订单号：{} 重复操作商户金额",storeUuid);
            return ApiResult.failure(String.format("订单号：%s 重复操作商户金额", storeUuid));
        }
        try {
            //cas 操作
            while (true) {

                int updateFlag = 0;
                StoreCapitalVirtualAccountDO storeCapitalVirtualAccount = this.getStoreCapitalVirtualAccountByStoreUuid(storeUuid);
                BigDecimal oldVirtualMoney = storeCapitalVirtualAccount.getVirtualmoney();
                BigDecimal oldFreezevirtualmoney = storeCapitalVirtualAccount.getFreezevirtualmoney();
                BigDecimal virtualmoney = oldVirtualMoney;
                BigDecimal freezevirtualmoney = oldFreezevirtualmoney;
                BigDecimal cashAmount = storeCapitalVirtualAccount.getCashAmount();
                BigDecimal balanceAmount = storeCapitalVirtualAccount.getBalanceAmount();
                BigDecimal integralAmount = storeCapitalVirtualAccount.getIntegralAmount();
                String uuid = storeCapitalVirtualAccount.getUuid();

                // 冻结
                if (StoreVirtualOperConstants.IN_FREEZE_MONEY.equals(operType)) {

                    // 校验
                    if (operAmount.compareTo(oldVirtualMoney) == 1) {
                        return ApiResult.failure("虚拟账户金额小于需要冻结金额");
                    }
                    freezevirtualmoney = oldFreezevirtualmoney.add(operAmount);
                    virtualmoney = oldVirtualMoney.subtract(operAmount);
                    // 详细资金的快照
                    balanceAmount = balanceAmount.subtract(operBalanceAmount);
                    cashAmount = cashAmount.subtract(operCashAmount);
                    integralAmount = integralAmount.subtract(operIntegralAmount);


                    //修改金额
                    updateFlag = updateMoney(uuid, virtualmoney, freezevirtualmoney, oldVirtualMoney, oldFreezevirtualmoney, cashAmount, balanceAmount, integralAmount);
                    if (updateFlag == 0) {
                        continue;
                    }
                    //做流水记录
                    storeCapitalVirtualAccountDetailService.createStoreAccountLog(storeUuid, storeCapitalVirtualAccount.getStoreno(), businessType, StoreVirtualOperConstants.OUT_MONEY, operAmount, virtualmoney, freezevirtualmoney, orderNo, description, customerUuid, cashAmount, balanceAmount, integralAmount, operCashAmount, operBalanceAmount, operIntegralAmount);
                    // 解冻
                } else if (StoreVirtualOperConstants.OUT_FREEZE_MONEY.equals(operType)) {

                    if (operAmount.compareTo(oldFreezevirtualmoney) == 1) {
                        return ApiResult.failure("虚拟账户的冻结金额小于需要解冻金额");
                    }
                    freezevirtualmoney = oldFreezevirtualmoney.subtract(operAmount);
                    virtualmoney = oldVirtualMoney.add(operAmount);
                    // 详细资金的快照
                    balanceAmount = balanceAmount.add(operBalanceAmount);
                    cashAmount = cashAmount.add(operCashAmount);
                    integralAmount = integralAmount.add(operIntegralAmount);

                    //修改金额
                    updateFlag = updateMoney(uuid, virtualmoney, freezevirtualmoney, oldVirtualMoney, oldFreezevirtualmoney, cashAmount, balanceAmount, integralAmount);
                    if (updateFlag == 0) {
                        continue;
                    }
                    //做流水记录
                    storeCapitalVirtualAccountDetailService.createStoreAccountLog(storeUuid, storeCapitalVirtualAccount.getStoreno(), businessType, StoreVirtualOperConstants.IN_MONEY, operAmount, virtualmoney, freezevirtualmoney, orderNo, description, customerUuid, cashAmount, balanceAmount, integralAmount, operCashAmount, operBalanceAmount, operIntegralAmount);
                } else {
                    return ApiResult.failure("未知操作类型");
                }
                return ApiResult.success();
            }
        }catch (Exception e){
            e.printStackTrace();
            log.error(e.getMessage());
        } finally {
            Object redisLockValue = redisUtils.getValue(redisLockKey);
            if (redisLockValue != null && timeStamp.equals(redisLockValue.toString())) {
                redisUtils.delKey(redisLockKey);
            }
        }
        return ApiResult.failure();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ApiResult dealFreezeVirtulaMoney(Map<String, Object> params) {

        Object temp = params.get("storeUuid");
        String storeUuid = temp != null ? temp.toString() : null;
        temp = params.get("orderNo");
        String orderNo = temp != null ? temp.toString() : null;
        temp = params.get("operFreezeAmount");
        BigDecimal operFreezeAmount = temp != null ? new BigDecimal(temp.toString()) : null;
        temp = params.get("customerUuid");
        String customerUuid = temp != null ? temp.toString() : null;
        temp = params.get("description");
        String description = temp != null ? temp.toString() : null;
        temp = params.get("operType");
        String operType = temp != null ? temp.toString() : null;
        temp = params.get("businessType");
        String businessType = temp != null ? temp.toString() : null;
        if (StringUtils.isBlank(storeUuid) || StringUtils.isBlank(orderNo) || StringUtils.isBlank(operType) || StringUtils.isBlank(customerUuid) || operFreezeAmount == null || StringUtils.isBlank(description)) {
            return ApiResult.paramIsNull();
        }

        String redisLockKey = "changeMoney" + storeUuid;
        String timeStamp = "" + System.currentTimeMillis();
        /**
         * 分布式锁
         */
        try {
            while (!redisUtils.setIfAbsent(redisLockKey, timeStamp, 3L)) {
                Thread.sleep(100L);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        //订单幂等性校验
        boolean isRepeat = isRepeatOrder(orderNo, storeUuid, businessType, operType);
        if(isRepeat){
            log.error("订单号：{} 重复操作商户金额",storeUuid);
            return ApiResult.failure(String.format("订单号：%s 重复操作商户金额", storeUuid));
        }

        try {
            while (true) {
                StoreCapitalVirtualAccountDO storeCapitalVirtualAccount = this.getStoreCapitalVirtualAccountByStoreUuid(storeUuid);
                int updateFlag = 0;
                BigDecimal oldVirtualMoney = storeCapitalVirtualAccount.getVirtualmoney();
                BigDecimal oldFreezevirtualmoney = storeCapitalVirtualAccount.getFreezevirtualmoney();
                BigDecimal virtualmoney = oldVirtualMoney;
                BigDecimal freezevirtualmoney = oldFreezevirtualmoney;
                // 详细金额快照
                BigDecimal cashAmount = storeCapitalVirtualAccount.getCashAmount();
                BigDecimal balanceAmount = storeCapitalVirtualAccount.getBalanceAmount();
                BigDecimal integralAmount = storeCapitalVirtualAccount.getIntegralAmount();
                // 详细金额操作明细
                BigDecimal operCashAmount = new BigDecimal(0);
                BigDecimal operBalanceAmount = new BigDecimal(0);
                BigDecimal operIntegralAmount = new BigDecimal(0);
                String uuid = storeCapitalVirtualAccount.getUuid();

                //虚拟账户入账
                if (StoreVirtualOperConstants.IN_FREEZE_MONEY.equals(operType)) {

                    freezevirtualmoney = oldFreezevirtualmoney.add(operFreezeAmount);
                    //修改金额
                    updateFlag = updateMoney(uuid, virtualmoney, freezevirtualmoney, oldVirtualMoney, oldFreezevirtualmoney, cashAmount, balanceAmount, integralAmount);

                    //虚拟账户出账
                } else if (StoreVirtualOperConstants.OUT_FREEZE_MONEY.equals(operType)) {

                    if (operFreezeAmount.compareTo(oldFreezevirtualmoney) == 1) {
                        return ApiResult.failure("虚拟账户冻结金额不足以减扣");
                    }
                    freezevirtualmoney = oldFreezevirtualmoney.subtract(operFreezeAmount);
                    //修改金额
                    updateFlag = updateMoney(uuid, virtualmoney, freezevirtualmoney, oldVirtualMoney, oldFreezevirtualmoney, cashAmount, balanceAmount, integralAmount);

                } else {
                    return ApiResult.failure("未知操作类型");
                }
                if (updateFlag == 0) {
                    continue;
                }
                //生成流水
                storeCapitalVirtualAccountDetailService.createStoreAccountLog(storeUuid, storeCapitalVirtualAccount.getStoreno(), businessType, operType, operFreezeAmount, virtualmoney, freezevirtualmoney, orderNo, description, customerUuid, cashAmount, balanceAmount, integralAmount, operCashAmount, operBalanceAmount, operIntegralAmount);

                return ApiResult.success();
            }
        } catch (Exception e){
            e.printStackTrace();
            log.error(e.getMessage());
        }finally {
            Object redisLockValue = redisUtils.getValue(redisLockKey);
            if (redisLockValue != null && timeStamp.equals(redisLockValue.toString())) {
                redisUtils.delKey(redisLockKey);
            }
        }
        return ApiResult.failure();
    }

    @Override
    public ApiResult manualwithdraw(Map<String, Object> params) {


        Object temp = params.get("storeUuid");
        String storeUuid = temp != null ? temp.toString() : null;
        temp = params.get("totalAmount");
        BigDecimal totalAmount = temp != null ? new BigDecimal(temp.toString()) : null;
        temp = params.get("operCashAmount");
        BigDecimal operCashAmount = temp != null ? new BigDecimal(temp.toString()) : null;
        temp = params.get("operBalanceAmount");
        BigDecimal operBalanceAmount = temp != null ? new BigDecimal(temp.toString()) : null;
        temp = params.get("operIntegralAmount");
        BigDecimal operIntegralAmount = temp != null ? new BigDecimal(temp.toString()) : null;
        temp = params.get("subject");
        String subject = temp != null ? temp.toString() : null;

        if (StringUtils.isBlank(storeUuid) || totalAmount == null || StringUtils.isBlank(subject)) {
            return ApiResult.paramIsNull();
        }
        if (totalAmount.compareTo(operBalanceAmount.add(operIntegralAmount).add(operCashAmount)) != 0 ){
            return ApiResult.failure("输入的总金额和金额明细不对等，请检查参数");
        }
        StoreCapitalVirtualAccountDO storeCapitalVirtualAccount = this.getStoreCapitalVirtualAccountByStoreUuid(storeUuid);
        StoreMainInfoDO storeMainInfo = storeMainInfoService.get(storeUuid);

        boolean isOperInteragralAmount = operIntegralAmount.compareTo(new BigDecimal(0)) != 0;
        boolean isOperCashAmount = operCashAmount.compareTo(new BigDecimal(0)) != 0;
        boolean isOperBalanceAmount = operBalanceAmount.compareTo(new BigDecimal(0)) != 0;

        String withdrawalType = null;
        if (!isOperInteragralAmount && !isOperBalanceAmount) {
            withdrawalType = StoreVirtualOperConstants.ENUM_TYPE_WITHDRAW_CASH;
        } else if (!isOperCashAmount) {
            withdrawalType = StoreVirtualOperConstants.ENUM_TYPE_WITHDRAW_BALANCE_INTEGRAL;
        } else {
            withdrawalType = StoreVirtualOperConstants.ENUM_TYPE_WITHDRAW_CASH_BALANCE_INTEGRAL;

        }

        return dealWithdraw(storeMainInfo, subject, storeUuid, storeCapitalVirtualAccount, totalAmount, operCashAmount, operBalanceAmount, operIntegralAmount, withdrawalType);
    }

    @Override
    public ApiResult withdraw() {


        Map<String, Object> queryMap = new HashMap<>();
        queryMap.put("delflag", CommonConstants.COMMON_FLAG_UNDEL);
        //Todo: 财务审核功能
        queryMap.put("auditstatus", StoreMainInfoEnum.BUSINESS_AUDIT_PASS);
        //queryMap.put("auditstatus", StoreMainInfoEnum.FINANCE_AUDIT_PASS);
        List<StoreMainInfoDO> list = storeMainInfoService.list(queryMap);

        for (StoreMainInfoDO storeMainInfoDO : list) {

            Map<String, Object> params = new HashMap<>();
            params.put("storeMainInfo", storeMainInfoDO);
            params.put("subject", "进行每日提现");

            try {
                withdraw(params);
            } catch (Exception e) {
                e.printStackTrace();
                log.error(e.getMessage());
            }

        }

        return ApiResult.success();
    }

    @Async
    @Override
    public ApiResult withdraw(Map<String, Object> params) {

        Object temp = params.get("storeMainInfo");
        StoreMainInfoDO storeMainInfo = temp != null ? (StoreMainInfoDO) temp : null;
        temp = params.get("subject");
        String subject = temp != null ? temp.toString() : null;

        if (storeMainInfo == null || StringUtils.isBlank(subject)) {
            return ApiResult.paramIsNull();
        }

        String storeUuid = storeMainInfo.getUuid();

        StoreCapitalVirtualAccountDO storeCapitalVirtualAccount = this.getStoreCapitalVirtualAccountByStoreUuid(storeUuid);

        BigDecimal virtualMoney = storeCapitalVirtualAccount.getVirtualmoney();

        //判断是否有提现资格提现金额
        if (virtualMoney.compareTo(new BigDecimal(10)) < 0) {
            log.error(String.format("金额不足10元 商户号：%s", storeUuid));
            return ApiResult.failure("金额不足10元");
        }
        //获取提现金额  今日0点余额 - 后一日0点的余额
        long current = System.currentTimeMillis();
        long zero = current - (current + TimeZone.getDefault().getRawOffset()) % (1000 * 3600 * 24);
        String nowDate = DateFormatHelper.dateTimeFormat(zero);
        zero = current - (current + TimeZone.getDefault().getRawOffset()) % (1000 * 3600 * 24) + (1000 * 3600 * 24);
        String AfterDate = DateFormatHelper.dateTimeFormat(zero);
        System.out.println("nowDate：" + nowDate);
        System.out.println("AfterDate：" + AfterDate);
        List<StoreCapitalVirtualAccountDetailDO> list = storeCapitalVirtualAccountDetailService.queryListByTime(nowDate, AfterDate, storeUuid);


        //今日流水
        BigDecimal nowAmount = new BigDecimal(0);
        //操作金额明细
        BigDecimal nowBalanceAmount = new BigDecimal(0);
        BigDecimal nowIntegralAmount = new BigDecimal(0);
        BigDecimal nowCashAmount = new BigDecimal(0);

        if (list != null && list.size() != 0) {
            for (StoreCapitalVirtualAccountDetailDO storeCapitalVirtualAccountDetail : list) {
                String businessType = storeCapitalVirtualAccountDetail.getBusinesstype();
                BigDecimal operAmount = storeCapitalVirtualAccountDetail.getOperamount();
                if (!(StoreVirtualOperConstants.PREFERENTIAL_ORDER_REFUND.equals(businessType) || StoreVirtualOperConstants.PREFERENTIAL_ORDER_SETTLE.equals(businessType) || StoreVirtualOperConstants.OPTIMAL_STORE_ORDER_REFUND.equals(businessType) || StoreVirtualOperConstants.OPTIMAL_STORE_ORDER_SETTLE.equals(businessType))) {
                    continue;
                }
                if (StoreVirtualOperConstants.IN_MONEY.equals(storeCapitalVirtualAccountDetail.getInorout())) {
                    nowAmount = nowAmount.add(operAmount);
                    nowBalanceAmount = nowBalanceAmount.add(storeCapitalVirtualAccountDetail.getOperBalanceAmount());
                    nowIntegralAmount = nowIntegralAmount.add(storeCapitalVirtualAccountDetail.getOperIntegralAmount());
                    nowCashAmount = nowCashAmount.add(storeCapitalVirtualAccountDetail.getOperCashAmount());
                } else if (StoreVirtualOperConstants.OUT_MONEY.equals(storeCapitalVirtualAccountDetail.getInorout())) {
                    nowAmount = nowAmount.subtract(operAmount);
                    nowBalanceAmount = nowBalanceAmount.subtract(storeCapitalVirtualAccountDetail.getOperBalanceAmount());
                    nowIntegralAmount = nowIntegralAmount.subtract(storeCapitalVirtualAccountDetail.getOperIntegralAmount());
                    nowCashAmount = nowCashAmount.subtract(storeCapitalVirtualAccountDetail.getOperCashAmount());
                }

            }

        }
        BigDecimal totalAmount = virtualMoney.subtract(nowAmount);
        BigDecimal operCashAmount = storeCapitalVirtualAccount.getCashAmount().subtract(nowCashAmount);
        BigDecimal operBalanceAmount = storeCapitalVirtualAccount.getBalanceAmount().subtract(nowBalanceAmount);
        BigDecimal operIntegralAmount = storeCapitalVirtualAccount.getIntegralAmount().subtract(nowIntegralAmount);


        if (operBalanceAmount.add(operIntegralAmount).add(operCashAmount).compareTo(totalAmount) != 0) {
            log.error(String.format("金额计算有误停止提现 商户号：%s", storeUuid));
            return ApiResult.failure("金额计算有误停止提现，不可提现");
        }

        if (totalAmount.compareTo(new BigDecimal(10)) < 0) {
            log.error(String.format("营业额不足10元，不可提现 商户号：%s", storeUuid));
            return ApiResult.failure("营业额不足10元，不可提现");
        }
        String withdrawalType = null;
        boolean isOperInteragralAmount = operIntegralAmount.compareTo(new BigDecimal(0)) != 0;
        boolean isOperCashAmount = operCashAmount.compareTo(new BigDecimal(0)) != 0;
        boolean isOperBalanceAmount = operBalanceAmount.compareTo(new BigDecimal(0)) != 0;
        if (!isOperInteragralAmount && !isOperBalanceAmount) {
            withdrawalType = StoreVirtualOperConstants.ENUM_TYPE_WITHDRAW_CASH;
        } else if (!isOperCashAmount) {
            withdrawalType = StoreVirtualOperConstants.ENUM_TYPE_WITHDRAW_BALANCE_INTEGRAL;
        } else {
            withdrawalType = StoreVirtualOperConstants.ENUM_TYPE_WITHDRAW_CASH_BALANCE_INTEGRAL;

        }


        return dealWithdraw(storeMainInfo, subject, storeUuid, storeCapitalVirtualAccount, totalAmount, operCashAmount, operBalanceAmount, operIntegralAmount, withdrawalType);
    }

    public ApiResult dealWithdraw(StoreMainInfoDO storeMainInfo, String subject, String storeUuid, StoreCapitalVirtualAccountDO storeCapitalVirtualAccount, BigDecimal totalAmount, BigDecimal operCashAmount, BigDecimal operBalanceAmount, BigDecimal operIntegralAmount, String withdrawType) {

        String withdrawalId = sysconfigFeign.getWithdrawalId();
        Map<String, Object> returnResult = new HashMap<>();
        returnResult.put("totalAmount", totalAmount);
        returnResult.put("storeUuid", storeUuid);
        returnResult.put("subject", subject);
        returnResult.put("bankName", storeCapitalVirtualAccount.getBankname());
        returnResult.put("cityName", storeCapitalVirtualAccount.getCityname());
        returnResult.put("bankAccountNo", storeCapitalVirtualAccount.getCompanyaccountno());
        returnResult.put("bankAccountName", storeCapitalVirtualAccount.getOpenaccountname());
        returnResult.put("withdrawalId", withdrawalId);
        returnResult.put("withdrawalType", withdrawType);

        String accoutType = storeCapitalVirtualAccount.getAccounttype();
        String bankAccoutType = "personal";
        if ("2".equals(accoutType)) {
            bankAccoutType = "corporate";
        }
        returnResult.put("bankAccountType", bankAccoutType);
        returnResult.put("bankCardType", storeCapitalVirtualAccount.getBankcardtype());
        returnResult.put("ysUserCode", storeMainInfo.getYsusercode());
        returnResult.put("ysUserStatus", storeMainInfo.getYsuserstate());
        returnResult.put("cashAmount", operCashAmount);
        returnResult.put("balanceAmount", operBalanceAmount);
        returnResult.put("integralAmount", operIntegralAmount);
        returnResult.put("totalAcountAmount",storeCapitalVirtualAccount.getVirtualmoney());
        log.error("totalAcountAmount:{}",storeCapitalVirtualAccount.getVirtualmoney());
        Map<String, Object> freezeParams = new HashMap<>();

        freezeParams.put("storeUuid", storeUuid);
        freezeParams.put("operAmount", totalAmount);
        freezeParams.put("operType", StoreVirtualOperConstants.IN_FREEZE_MONEY);
        freezeParams.put("businessType", StoreVirtualOperConstants.ORDER_WITHDRAW);
        freezeParams.put("customerUuid", storeUuid);
        freezeParams.put("orderNo", withdrawalId);
        freezeParams.put("description", String.format(StoreVirtualOperConstants.FREEZE_WITHDRAW, withdrawalId, totalAmount));
        freezeParams.put("operCashAmount", operCashAmount);
        freezeParams.put("operBalanceAmount", operBalanceAmount);
        freezeParams.put("operIntegralAmount", operIntegralAmount);

        // 冻结
        ApiResult freezeResult = this.freezeOrUnFreezeVirtualMoney(freezeParams);
        if (!ApiResultCode.SUCCESS.code().equals(freezeResult.getCode())) {
            return ApiResult.failure();
        }
        // 提现
        ApiResult withdrawlResult = null;
        try {
            withdrawlResult = settleFeign.createWithdrawal(returnResult);
            if (!ApiResultCode.SUCCESS.code().equals(withdrawlResult.getCode())) {
                log.error("提现失败提示：" + JSONUtils.beanToJson(withdrawlResult));
                throw new Exception(String.format("商户：%s提现失败", storeUuid));
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error(e.getMessage());
            Map<String, Object> unFreezeParams = freezeParams;
            unFreezeParams.put("description", String.format(StoreVirtualOperConstants.ERRER_FREEZE_WITHDRAW, withdrawalId, totalAmount));
            unFreezeParams.put("operType", StoreVirtualOperConstants.OUT_FREEZE_MONEY);
            this.freezeOrUnFreezeVirtualMoney(freezeParams);
            return ApiResult.failure(e.getMessage());
        }
        ApiResult dealFreezeResult = this.dealFreezeVirtulaMoney((Map<String, Object>) withdrawlResult.getResult());

        if (!ApiResultCode.SUCCESS.code().equals(dealFreezeResult.getCode())) {

            log.error(String.format("商户%s提现减扣冻结余额失败", storeUuid));

            return ApiResult.failure();
        }
        return ApiResult.success();
    }

    @Override
    public Map virtualAccountPassword(Map<String, Object> params) {
        return storeCapitalVirtualAccountDao.virtualAccountPassword(params);
    }

    @Override
    public String getAccontPwdByCounterId(String counterId) {
        return storeCapitalVirtualAccountDao.getAccontPwdByCounterId(counterId);
    }

}
